package app

import (
	"encoding/json"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type (
	ApiService struct{}
	Context    struct {
		Service  *Server             //
		Response http.ResponseWriter //
		Request  *http.Request       //
		URL      string              //
		Method   string              //
		FuncName string              //
		Header   map[string]string   //需要输出的header
	}

	StaticFiles []string
)

var sessionCookieName string = "_dockerSync"

func (sf *StaticFiles) ParseStaticFiles(fileDir string) {
	files, _ := ioutil.ReadDir(fileDir)
	for _, oneFile := range files {
		if oneFile.IsDir() {
			sf.ParseStaticFiles(fileDir + string(os.PathSeparator) + oneFile.Name())
		} else {
			*sf = append(*sf, oneFile.Name())
		}
	}
}

/**
新建会话
*/
func NewContext(res http.ResponseWriter, req *http.Request, ser *Server) *Context {
	ctx := new(Context)
	ctx.Service = ser
	ctx.Request = req
	ctx.Response = res
	ctx.URL = strings.ToLower(req.URL.Path)
	ctx.Method = strings.ToUpper(req.Method)
	ctx.Header = make(map[string]string)

	//处理登陆Session
	sCookie, err := req.Cookie(sessionCookieName)
	if err != nil || sCookie.Value == "" || len(sCookie.Value) != 16 {
		cookieVal := GetRandomString(16)
		http.SetCookie(res, &http.Cookie{
			Name:     sessionCookieName,
			Value:    cookieVal,
			HttpOnly: true,
			Path:     "/",
			Expires:  time.Now().AddDate(0, 1, 0),
		})

	}

	if ctx.URL == "" || ctx.URL == "/" || string(ctx.URL[0]) != "/" {
		ctx.FuncName = "Index"
	} else {
		for _, v := range strings.Split(string(ctx.URL[1:]), "/") {
			ctx.FuncName += strings.Title(v)
		}
	}
	if ctx.Method != "GET" {
		ctx.FuncName = "Do" + ctx.FuncName
	}

	return ctx
}

/**
Success
*/
func (ctx *Context) Success(data interface{}) {
	ctx.Show(0, "success", data)
}

/**
Error
*/
func (ctx *Context) Error(errNo int64, errStr string) {
	ctx.Show(errNo, errStr, nil)
}

/**
show JSON
*/
func (ctx *Context) Show(errNo int64, errStr string, data interface{}) {
	ctx.Response.Header().Set("Content-Type", "application/json")
	api := ApiController{ErrNo: errNo, ErrStr: errStr, Data: data}

	bytes, err := json.Marshal(api)
	if err != nil {
		bytes = []byte("system error")
		P("Json.Marshal.Error", err.Error(), "error")
		return
	}

	_, err = ctx.Response.Write(bytes)
	return
}

func (ctx *Context) ShowHtml(httpCode int, html string) {
	ctx.Response.WriteHeader(httpCode)
	ctx.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
	ctx.Response.Header().Set("Date", time.Now().Format(time.RFC1123))
	_, _ = ctx.Response.Write([]byte(html))
	return
}

/**
未知请求
*/
func (ctx *Context) PageNotFound() {
	ctx.Error(1, "Page not found")
}

/**
未经过允许的访问
*/
func (ctx *Context) PageAccessNotAllowed(clientIp string) {
	ctx.Show(1, "Access is not allowed.", clientIp)
}

//页面跳转
type RedirectPageData struct {
	PageTitle   string //显示的标题
	Msg         string //显示的提示信息
	IsSuccess   bool   //是否成功提示
	RedirectUrl string //要跳转的页面
	WaitSecond  int    //等待的时间
}

/**
显示成功页面
*/
func (ctx *Context) ShowSuccessPage(msg, redirect string, waitSecond int) {
	data := RedirectPageData{
		PageTitle:   "Title",
		Msg:         msg,
		IsSuccess:   true,
		RedirectUrl: redirect,
		WaitSecond:  waitSecond,
	}
	_ = ctx.View("redirect.html", data, 200, "template/redirect.html", "template/include.html")
}

/**
显示错误页面
*/
func (ctx *Context) ShowErrorPage(msg, redirect string, waitSecond int) {
	data := RedirectPageData{
		PageTitle:   "Title",
		Msg:         msg,
		IsSuccess:   false,
		RedirectUrl: redirect,
		WaitSecond:  waitSecond,
	}
	_ = ctx.View("redirect.html", data, 200, "template/redirect.html", "template/include.html")
}

/**
渲染模版
*/
func (ctx *Context) View(pageName string, data interface{}, httpCode int, pages ...string) (err error) {
	t := template.New(pageName).Funcs(FuncMap)

	if pages[0] != "" {
		t, err = t.ParseFiles(pages...)
		if err != nil {
			http.Error(ctx.Response, err.Error(), http.StatusInternalServerError)
			return err
		}
	}

	ctx.Response.WriteHeader(httpCode)
	ctx.Header["Content-Type"] = "text/html;charset=utf-8"

	for k, v := range ctx.Header {
		ctx.Response.Header().Set(k, v)
	}

	err = t.Execute(ctx.Response, data)
	return
}

/**
直接输出字符串
*/
func (ctx *Context) Echo(str string) {
	for k, v := range ctx.Header {
		ctx.Response.Header().Set(k, v)
	}

	_, _ = ctx.Response.Write([]byte(str))
}
